home *** CD-ROM | disk | FTP | other *** search
-
- INCLUDE C:\ASM\EQUATES.ASM
-
- INCLUDE C:\ASM\MACROS.ASM
-
- CSEG SEGMENT PARA PUBLIC 'CODE'
-
- ASSUME CS:CSEG,DS:CSEG
-
- ORG 0100H
-
- ;
- ; This equate controls where the files are written. If TO_Z80_DIR is EQUated
- ; to 1, then all files read from the floppy will be written to the path
- ; "C:\Z80". If TO_Z80_DIR is EQUated to 0, then all files will be written to
- ; the current default path.
- ;
- TO_Z80_DIR EQU 1 ; Need to define it
-
- DIR_ENTRY_SIZE EQU 32 ; 32 bytes for each dir entry
- MAX_DIR_ENTRIES EQU 64 ; Max number of dir entries
- NUM_TRACKS EQU 78 ; Number of tracks to read (* 2)
- BLOCKS_PER_TRK EQU 2 ; Number of logical blks per trk
- RECORDS_PER_BLK EQU 16 ; # of logical (128-byte) records
- ; per block
- SECTORS_PER_BLK EQU 8 ; Number of physical (256-byte) sectors
- ; per blk
- SECTOR_SIZE EQU 256 ; Size of disk sector
- SHIFT EQU 8 ; Log2 of sector size
- SPT EQU 16 ; Sectors per track
- BYTES_PER_TRACK EQU SECTOR_SIZE*SECTORS_PER_BLK*BLOCKS_PER_TRK
- RETRY_COUNT EQU 5 ; Retry count for floppy read
-
- START PROC FAR
-
- CALL INITIALIZE ; Set up
- CALL LOAD_DISK ; Read entire floppy into memory
- CALL WRITE_FILES ; Write files according to dir
- MOV AX,4C00H ; Exit w/no error
- INT 21H
-
- START ENDP
-
- ;
- ; Once-only initialization. Reset SP, get current disk parameters, set up
- ; table of addresses for blocks & track
- ;
- INITIALIZE PROC NEAR
-
- POP SI ; Save return address
- CLI ; Can't be interrupted...
- LEA SP,STACK_TOP ; while SP is changed
- STI ; Ints ok now
- PUSH SI ; Put return address back
- MOV AX,351EH ; Get INT 1EH vector. This points
- INT 21H ; to the diskette parameters.
- MOV OLD_DISK_PTR,BX
- MOV OLD_DISK_PTR+2,ES ; Save old parameters...
- PUSH DS ; Swap segments
- PUSH ES
- POP DS
- POP ES
- MOV SI,BX ; Point to the current parameters
- LEA DI,DISK_TABLE ; And the ones I want to set
- MOV CX,11 ; Copy old to new
- REP MOVSB
- PUSH CS
- POP DS
- MOV BYTE PTR BPS,SECTOR_SIZE/256 ; Reset bytes per sector
- MOV BYTE PTR DTL,0FFH ; Still a mystery...
- MOV BYTE PTR EOT,SPT ; Reset sectors per track
- MOV BYTE PTR HST,0 ; Set to no head settle time
- MOV BYTE PTR MST,0 ; ... and no motor start delay
- SUB AX,AX ; BIOS function 0
- INT 13H ; (reset diskette system)
- LEA DI,BLOCKS ; Fill in the "BLOCKS" table
- LEA AX,STACK_TOP ; Get last program addr
- ADD AX,16 ; Align on a para boundary
- MOV CL,4
- SHR AX,CL
- MOV CX,CS
- ADD AX,CX ; Make it absolute
- MOV CX,NUM_TRACKS*BLOCKS_PER_TRK
- INIT_L1:
- STOSW ; Put away a table entry
- ADD AX,(BYTES_PER_TRACK/BLOCKS_PER_TRK)/16
- LOOP INIT_L1
- MOV TRACK_BUFFER,AX
- RET
-
- INITIALIZE ENDP
-
- ;
- ; Routine to load the entire floppy disk into RAM. Track-to-block translation
- ; is done once the track is in memory
- ;
- LOAD_DISK PROC NEAR
-
- MOV AX,CS
- MOV DS,AX ; Make sure the segs are local
- MOV ES,AX
- LEA DX,PUT_IN_DISK ; Display prompt message
- MOV AH,9
- INT 21H
- MOV AH,1 ; And read a character
- INT 21H
- CALL CRLF
- LEA DX,LOADING_MESS ; Let me know what's going on...
- MOV AH,9
- INT 21H
- LEA DI,BLOCKS ; Point to pointer table
- MOV CX,NUM_TRACKS ; Number of tracks to read
- ;
- ; Note that track 0 & 1 (system tracks) are not read.
- ;
- LD_L1:
- CALL READ_SECTOR ; Read in a track
- INC BYTE PTR CURR_HEAD ; Indicate next head
- AND BYTE PTR CURR_HEAD,1 ; Mod 2
- JNZ LD_L2 ; If changes from 1 to 0,
- INC BYTE PTR CURR_TRACK ; go to next track
- ;
- LD_L2:
- MOV AX,1 ; Starting at sector 1,
- CALL COPY_BLOCK ; copy from the track to a block
- INC DI ; Point to next table entry
- INC DI
- MOV AX,SECTORS_PER_BLK+1 ; Now start at next block
- CALL COPY_BLOCK ; And copy
- INC DI
- INC DI
- MOV AL,'.' ; Tell me that 1 more has been read
- CALL PCHAR
- LOOP LD_L1 ; Do all tracks but 0
- CALL CRLF
- RET
-
- LOAD_DISK ENDP
-
-
- ;
- ; Routine to copy from the track buffer to the block at (DI^)^. This routine
- ; assumes an interleave ("skew" under CP/M) of 3:1; i.e., to read a block
- ; starts at sector 1, the sectors must be read in this order:
- ; 1,4,7,10,13,16,3,6. A block that starts on sector 9: 9,12,15,2,5,8,11,14.
- ;
- COPY_BLOCK PROC NEAR
-
- SAVE_REG AX,CX,SI,DI,DS,ES
- MOV DS,CS:TRACK_BUFFER ; Point to track buffer
- MOV ES,CS:[DI] ; Need seg for this block
- SUB DI,DI ; Copy to offset 0
- MOV CX,SECTORS_PER_BLK ; This many sectors
- CB_L1:
- PUSH CX ; Save outer loop count
- MOV SI,AX ; Get sector number
- DEC SI ; ......
- MOV CL,SHIFT ; ......
- SHL SI,CL ; Make it an offset
- MOV CX,SECTOR_SIZE ; Move one sector to block buffer
- REP MOVSB
- INC AX ; Calculate next sector to read
- INC AX ; S = (S + 2)
- AND AX,0FH ; S = ((S + 2) MOD 16)
- INC AX ; S = ((S + 2) MOD 16) + 1
- POP CX
- LOOP CB_L1 ; Do all sectors in this block
- RESTORE
- RET
-
- COPY_BLOCK ENDP
-
-
- ;
- ; Control routine to copy files from the block buffers to the appropriate DOS
- ; files according to the directory at BLOCK[0].
- ;
- WRITE_FILES PROC NEAR
-
- SAVE_REG AX,BX,CX,SI,DI,DS,ES
- SUB BX,BX ; Set up parameters
- MOV CX,MAX_DIR_ENTRIES ; Number of entries to scan
- WF_L1:
- PUSH CX ; Save the loop count
- MOV DS,CS:BLOCKS ; Point to directory block
- CMP BYTE PTR [BX],0E5H ; Is this a deleted file?
- JE WF_CONT ; Continue the loop if it is
- CMP BYTE PTR [BX+12],2 ; Is this a continuation extent?
- JAE WF_CONT ; Continue the loop if it is
- MOV CS:FILE_SIZE,0 ; Start with that record size
- CALL COPY_NAME ; Copy the file name
- PUSH CS
- POP DS ; Reset to local seg
- CALL ASK_ME ; Ask me if I want to copy it
- CMP AL,'Y' ; If I said "N", then ignore it
- JNE WF_CONT
- CALL OPEN_FILE ; Open the output file
- LEA DX,WRITING_MESS ; Tell me the file being written
- MOV AH,9
- INT 21H
- LEA SI,FILE_NAME
- CALL PSTRING ; Tell me the file name
- CALL PUT_FILE ; Save the file
- POP CX
- PUSH CX
- CALL FIND_OTHERS ; Find any other extents for that file
- MOV AL,';' ; More info;
- CALL PCHAR
- MOV AL,SPACE
- CALL PCHAR
- MOV AX,CS:FILE_SIZE ; Show file size in 128-byte records
- CALL PDECI
- LEA SI,RECS_MESS
- CALL PSTRING
- CALL CLOSE_FILE ; Now close it
- ;
- WF_CONT:
- ADD BX,DIR_ENTRY_SIZE ; Point to next entry
- POP CX ; Restore the loop count
- LOOP WF_L1
- RESTORE
- RET
-
- WRITE_FILES ENDP
-
-
- ;
- ; This routine displays a single file name (from the floppy directory), and
- ; prompts the user for a Y(es) or N(o) answer as to whether or not to copy
- ; the named file.
- ;
- ASK_ME PROC NEAR
-
- SAVE_REG DX,SI
- LEA DX,WRITE_QUERY
- MOV AH,9
- INT 21H
- LEA SI,NAME_BUF
- CALL PSTRING
- MOV AL,'?'
- CALL PCHAR
- MOV AL,SPACE
- CALL PCHAR
- CALL YES_OR_NO
- RESTORE
- RET
-
- ASK_ME ENDP
-
-
- YES_OR_NO PROC NEAR
-
- MOV AH,7
- MOV DL,0FFH
- INT 21H
- CMP AL,'a'
- JB YORN_L1
- CMP AL,'z'+1
- JAE YORN_L1
- SUB AL,32
- YORN_L1:
- CMP AL,'Y'
- JE YORN_RET
- CMP AL,'N'
- JNE YES_OR_NO
- YORN_RET:
- CALL PCHAR
- CALL CRLF
- RET
-
- YES_OR_NO ENDP
-
-
- ;
- ; Search the directory for any other entries matching the current entry,
- ; and write them to the file, too.
- ;
- FIND_OTHERS PROC NEAR
-
- SAVE_REG AX,BX,CX,SI,DI,DS,ES
- MOV DS,CS:BLOCKS ; Point to the directory
- MOV ES,CS:BLOCKS ; Twice
- MOV DI,BX ; Get current entry
- ADD DI,DIR_ENTRY_SIZE ; Point to next (to start)
- DEC CX ; One less to search
- FO_L1:
- MOV SI,BX ; Point to the current one
- INC SI ; Skip user number
- PUSH DI ; Save pointer to other
- CMP BYTE PTR ES:[DI],0E5H ; Is this a deleted entry?
- JE FO_L2 ; If so, skip it
- CMP BYTE PTR ES:[DI+12],1 ; Is this a starting extent?
- JBE FO_L2 ; If so, skip it
- INC DI ; Skip user number on this one
- PUSH CX ; Save search count
- MOV CX,11 ; Compare 11 bytes
- REPE CMPSB ; Names match?
- POP CX ; Get search count back
- JNZ FO_L2 ; If no match, continue search
- SUB DI,12 ; Point to name again
- XCHG BX,DI ; Save and point at same time
- CALL PUT_FILE ; Put these blocks in the file
- XCHG BX,DI ; Get the dir ptr back
- ;
- FO_L2:
- POP DI ; Restore "other" pointer
- ADD DI,DIR_ENTRY_SIZE ; Point to next
- LOOP FO_L1 ; Loop away
- RESTORE
- RET
-
- FIND_OTHERS ENDP
-
-
- ;
- ; Routine to copy the file name to ASCIIZ format for opening.
- ;
- COPY_NAME PROC NEAR
-
- SAVE_REG AX,CX,SI,DI,DS
- MOV SI,BX ; Point to the dir entry
- INC SI ; Skip the user number
- LEA DI,NAME_BUF ; Point to the file name area
- MOV CX,8 ; Max number to copy
- CALL COPY_PART ; Copy the first part
- MOV AL,'.' ; Put in the separator
- STOSB
- MOV CX,3 ; Max number of bytes in ext
- CALL COPY_PART ; Copy it
- SUB AL,AL ; Terminate with a null
- STOSB
- RESTORE
- RET
-
- COPY_NAME ENDP
-
-
- ;
- ; Routine to copy part of the file name from the dir entry to the local
- ; copy of the file name.
- ;
- COPY_PART PROC NEAR
-
- LODSB ; Pick up a byte
- AND AL,7FH ; Don't care about 8th bit
- CMP AL,SPACE ; Is it the end?
- JE CN_L1
- STOSB ; Put the byte away
- CN_L1:
- LOOP COPY_PART ; Loop for whatever
- RET ; Return to caller
-
- COPY_PART ENDP
-
-
- ;
- ; Routine to open the file @FILE_NAME
- ;
- OPEN_FILE PROC NEAR
-
- SAVE_REG AX,BX,CX,DX,DS
- PUSH CS
- POP DS
- LEA DX,FILE_NAME ; Open the file @FILE_NAME
- MOV AH,3CH
- SUB CX,CX
- INT 21H
- JNC OPFL_L1 ; If error then let me know
- PUSH AX
- LEA DX,OPEN_ERROR
- MOV AH,9
- INT 21H ; Display "open error" message
- LEA SI,FILE_NAME ; Display the file name
- CALL PSTRING
- MOV AL,':'
- CALL PCHAR
- POP AX
- CALL PDECI
- MOV AX,4C01H
- INT 21H ; Exit w/error to DOS
- ;
- OPFL_L1:
- MOV HANDLE,AX ; Save the file handle
- RESTORE
- RET
-
- OPEN_FILE ENDP
-
-
- ;
- ; Routine to close the current file
- ;
- CLOSE_FILE PROC NEAR
-
- SAVE_REG AX,BX
- MOV AH,3EH
- MOV BX,CS:HANDLE
- INT 21H
- RESTORE
- RET
-
- CLOSE_FILE ENDP
-
-
- ;
- ; Routine to copy the current block to the output file
- ;
- SAVE_FILE PROC NEAR
-
- SAVE_REG AX,BX,CX,DX
- MOV BX,CS:HANDLE ; Get the handle to write to
- MOV AX,CS:FILE_COUNT ; Get number of bytes to write
- MOV CL,7
- SHL AX,CL
- MOV CX,AX
- SUB DX,DX ; Write from offset 0...
- MOV AH,40H
- INT 21H
- JNC SAVE_L1 ; If error occurred, tell me
- PUSH CS
- POP DS
- LEA DX,ERROR_MESS
- MOV AH,9
- INT 21H
- LEA SI,FILE_NAME
- CALL PSTRING
- CALL CLOSE_FILE ; Salvage what we can...
- MOV AX,4C02H
- INT 21H
- ;
- SAVE_L1:
- RESTORE
- RET
-
- SAVE_FILE ENDP
-
-
- ;
- ; Routine to control which blocks get copied to the output file. Reads the
- ; list of blocks in the current dir entry.
- ;
- PUT_FILE PROC NEAR
-
- SAVE_REG AX,CX,SI,DS
- MOV DS,CS:BLOCKS
- MOV SI,BX ; Point to the current dir entry
- ADD SI,15 ; Point to the block list & size
- MOV CL,[SI]
- SUB CH,CH ; Get number of records for this extent
- TEST BYTE PTR [SI-3],1 ; Is the extent number odd?
- JZ PUTF_L11 ; If not, leave record count alone
- ADD CX,80H ; If extent number is odd, then it
- ; means that there are 2 extents
- ; referenced by the dir entry, and
- ; the record count is for the 2nd
- ; extent; the first extent takes up
- ; 80H(128d) records. Adjust the
- ; record count accordingly.
- PUTF_L11:
- JCXZ PUTF_RET ; Return if size is 0
- INC SI ; First block of file
- MOV AH,16 ; Max number of blocks per extent
- PUTF_L1:
- LODSB ; Pick up the block number
- OR AL,AL ; Is it 0?
- JZ PUTF_RET ; Return if so
- CMP CX,RECORDS_PER_BLK ; Are there at least that many left?
- JB PUTF_L2 ; If not, just write that many.
- SUB CX,RECORDS_PER_BLK
- MOV CS:FILE_COUNT,RECORDS_PER_BLK
- ADD CS:FILE_SIZE,RECORDS_PER_BLK
- JMP SHORT PUTF_L3
- PUTF_L2:
- MOV CS:FILE_COUNT,CX
- ADD CS:FILE_SIZE,CX
- PUTF_L3:
- PUSH AX ; Save the block number
- PUSH SI
- PUSH DS
- SUB AH,AH
- SHL AX,1
- MOV SI,AX
- MOV DS,CS:BLOCKS[SI]
- CALL SAVE_FILE
- POP DS
- POP SI
- POP AX
- DEC AH
- JNZ PUTF_L1 ; Loop for all blocks
- ;
- PUTF_RET:
- RESTORE
- RET
-
- PUT_FILE ENDP
-
- ;
- ; Simple utility routines called by most of the above
- ;
- CRLF PROC NEAR
-
- PUSH AX
- MOV AL,CR
- CALL PCHAR
- MOV AL,LF
- CALL PCHAR
- POP AX
- RET
-
- CRLF ENDP
-
-
- PDECI PROC NEAR
-
- SAVE_REG AX,BX,DX
- SUB BX,BX ; Put a flag word on the stack
- PUSH BX
- MOV BX,10 ; Divisor for decimal conversion
- PDECI_L1:
- SUB DX,DX ; Clear high word for division
- DIV BX ; Divide number by 10
- OR DL,30H ; Make the digit ASCII
- PUSH DX ; And save it
- OR AX,AX ; See if we're done yet
- JNZ PDECI_L1 ; If not, keep going
- PDECI_L2:
- POP AX ; Get a previously saved digit
- OR AX,AX ; See if it's the flag word
- JZ PDECI_L3 ; If it is, we're done
- CALL PCHAR ; Display the digit
- JMP SHORT PDECI_L2 ; Do the rest
- ;
- PDECI_L3:
- RESTORE
- RET
-
- PDECI ENDP
-
-
- PSTRING PROC NEAR
-
- SAVE_REG AX,SI,DS
- PUSH CS
- POP DS ; Make sure seg is right
- PSTR_L1:
- LODSB ; Pick up a byte of the string
- OR AL,AL ; Is it terminator?
- JZ PSTR_RET ; If it is, exit
- CALL PCHAR
- JMP SHORT PSTR_L1
- ;
- PSTR_RET:
- RESTORE
- RET
-
- PSTRING ENDP
-
-
- PCHAR PROC NEAR
-
- SAVE_REG AX,DX
- MOV DL,AL
- MOV AH,2
- INT 21H
- RESTORE
- RET
-
- PCHAR ENDP
-
-
- ;
- ; Routine to read 1 track from the floppy
- ;
- READ_SECTOR PROC NEAR
-
- SAVE_REG AX,BX,CX,DX,ES
- MOV AX,251EH
- LEA DX,DISK_TABLE
- INT 21H ; Set disk parameters
- MOV CX,RETRY_COUNT ; Get the retry count
- ;
- READ_SECTOR_L1:
- PUSH CX ; Save current retry count
- SUB DL,DL ; Always use A: drive
- MOV DH,CS:CURR_HEAD ; Pick up BIOS parameters
- MOV CL,1
- MOV CH,CS:CURR_TRACK
- MOV ES,CS:TRACK_BUFFER
- SUB BX,BX
- MOV AL,SPT
- MOV AH,2 ; Read 1 track
- INT 13H ; Via ROM BIOS
- POP CX
- JNC READ_SECTOR_L2 ; If no error, then finish
- LOOP READ_SECTOR_L1 ; Otherwise, keep re-trying
- LEA DX,FL_ERROR_MESS ; Display the error message
- PUSH CS
- POP DS
- MOV AH,9
- INT 21H
- MOV DX,CS:OLD_DISK_PTR
- MOV DS,CS:OLD_DISK_PTR+2
- MOV AX,251EH
- INT 21H
- MOV AX,4C03H
- INT 21H
- ;
- READ_SECTOR_L2:
- PUSH DS
- MOV DX,CS:OLD_DISK_PTR ; Restore old parameters
- MOV DS,CS:OLD_DISK_PTR+2
- MOV AX,251EH
- INT 21H
- POP DS
- RESTORE
- RET
-
- READ_SECTOR ENDP
-
-
- DISK_TABLE DB 0
- DB 0
- DB 0
- BPS DB 0
- EOT DB 0
- DB 0
- DTL DB 0
- DB 0
- DB 0
- HST DB 0
- MST DB 0
-
- OLD_DISK_PTR DW 0
- DW 0
-
- CURR_HEAD DB 0
- CURR_TRACK DB 1
-
- LOADING_MESS DB 'Reading diskette',CR,LF,'$'
- PUT_IN_DISK DB 'Put CP/M diskette in drive A:, then press any key $'
- OPEN_ERROR DB '? Error opening $'
- WRITE_QUERY DB 'Copy $'
- WRITING_MESS DB 'Writing $'
- RECS_MESS DB ' records written',CR,LF,0
- ERROR_MESS DB '? Error writing to $'
- FL_ERROR_MESS DB '? Error reading floppy drive',CR,LF,'$'
-
- IF TO_Z80_DIR
- FILE_NAME DB 'C:\Z80\'
- ELSE
- FILE_NAME LABEL BYTE
- ENDIF
- NAME_BUF DB 13 DUP(0)
-
- FILE_SIZE DW 0
-
- HANDLE DW 0
-
- TRACK_BUFFER DW 0
-
- BLOCKS DW NUM_TRACKS*BLOCKS_PER_TRK DUP(0)
-
- FILE_COUNT DW 0
- FILE_BUFFER DW 0
-
- EVEN
-
- DW 256 DUP(0)
-
- STACK_TOP = $
-
-
- CSEG ENDS
-
- END START